/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.sys>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /***************************************************************************
 * Name: method_parser.cpp
 *
 * Purpose: parser method block in sidl file.
 *
 * Developer:
 *   wen.gu , 2021-04-29
 *
 * TODO:
 *
 ***************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "method_parser.h"
#include "utils.h"
#include "key_word.h"
/******************************************************************************
 **    MACROS
 ******************************************************************************/


/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/
#if 0
static bool ParseOneArg(const DataTypeArray& type_defs, MethodArgument& arg, const YAML::Node& nd)
{
    if (!HasMember(nd, KW_METHOD_ARG_DIR) || !HasMember(nd, KW_TYPE))
    {
        return false;
    }

    std::string type_str = nd[KW_TYPE].as<std::string>();

    if (!HasTypeDef(type_defs, type_str))
    {
        PrintTypeError(nd, "the argument type: ", type_str, " is invailid(maybe not define before current line)");
        return false;
    }
    std::string dir_str = nd[KW_METHOD_ARG_DIR].as<std::string>();
    MethodArgumentDir dir = Str2ArgumentDir(dir_str);

    if (dir == MethodArgumentDir::kUnknown)
    {
        PrintTypeError(nd, "unknown argument dir: ", dir_str, " only support: input, output");
        return false;
    }


    arg.type = type_str;
    arg.dir = dir;

    return true;

}


static bool CheckReturnType(const DataTypeArray& type_defs, const std::string& type)
{
    if (!HasTypeDef(type_defs, type) && (type != KW_TYPE_VOID))
    {
        return false;
    }

    return true;
}
#endif

static bool ParseMethod(const DataTypeArray& type_defs, MethodInfo& method_info, const YAML::Node& nd)
{
    MethodInfo mi;

    if (HasMember(nd, KW_METHOD_ARGUMENTS))
    {
        const YAML::Node nd_args = nd[KW_METHOD_ARGUMENTS];
        if (!nd_args.IsMap())
        {          
            PrintError(nd_args, "the argument list must be a object");
            return false;
        }

        if (!ParseDataElementArray(type_defs, mi.arguments, nd_args))
        {
            return false;    
        }
    }

    if (HasMember(nd, KW_METHOD_RETURN))
    {
        const YAML::Node nd_return = nd[KW_METHOD_RETURN];
        if (!nd_return.IsScalar())
        {
            PrintError(nd_return, "the return type of method must be a scalar");
            return false;
        }
        mi.return_type = nd_return.as<std::string>();

        if (!HasTypeDef(type_defs, mi.return_type))
        {
            PrintTypeError(nd_return, "the type of method return: ", mi.return_type, " not defined before current reference");
            return false;    
        }
    }

    ParseComment(nd, mi.comment);
    
    return true;
}

/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/

MethodParser::MethodParser()
    :ContentParser(ContentType::kMethod)
{
    /** todo something */
}

MethodParser::~MethodParser()
{
    /** todo something */
}


bool MethodParser::parse(const YAML::Node& sidl, FileContent& file_content) 
{
    if (!sidl.IsMap())
    {
        return false;
    }
    
    MethodArray& methods = file_content.methods;
    for (YAML::Node::const_iterator it = sidl.begin(); it != sidl.end(); ++it )
    {        
        if (!it->first.IsScalar())
        {
            PrintError(it->first, "the name of method node must be scalar");
            return false;            
        }

        MethodInfo mi;
        mi.name = it->first.as<std::string>();

        if (!it->second.IsMap())
        {
            PrintTypeError(it->first, "the method define node: ", mi.name, " must be a object");
            return false;            
        }

        if (!ParseMethod(file_content.type_defs, mi, it->second))
        {
            PrintTypeError(it->first, "parse method: ", mi.name, " failed");
            return false;
        }

        methods.push_back(std::move(mi));
    }

    return true;

}



